/*
 * A class to represent a tic-tac-toe board, with elements
 * represented as single characters.
 * It allows moves to be made and reports the piece at
 * any place.  Originally, all pieces are set to blanks.
 * 
 * @author Jovan Munroe
 * @version 16 Sep 2013
 */
public class TicTacToeBoard {
	private int DIMENSION = 3;
	private final char DEFAULT_CHAR = ' ';
	private final char[][] board; // A 2D array to hold the elements of the board

	/**
	 * Construct a tic-tac-toe board, initially all blank.
	 */
	public TicTacToeBoard() {
		DIMENSION = 3;
		board = new char[DIMENSION][DIMENSION];

		// Set it to all blanks
		for (int row = 0; row < DIMENSION; row++) {
			for (int col = 0; col < DIMENSION; col++) {
				board[row][col] = DEFAULT_CHAR;
			}
		}
	}

	/**
	 * Constructs a tic tac toe board with given dimensions Uses 3 if dimension
	 * is negative
	 * 
	 * @param dimension integer for the board size
	 */
	public TicTacToeBoard(int dimension) {
		if (dimension < 0) {
			dimension = 3;
			DIMENSION = 3;
		} else {
			DIMENSION = dimension;
		}

		board = new char[dimension][dimension];

		// Set it to all blanks
		for (int row = 0; row < dimension; row++) {
			for (int col = 0; col < dimension; col++) {
				board[row][col] = DEFAULT_CHAR;
			}
		}
	}

	/**
	 * Set a piece on the board only if space is blank and within bounds.
	 * 
	 * @param row
	 *            the row of the new piece
	 * @param column
	 *            the column of the new piece (Precondition: row and column
	 *            indicate a valid empty place on the board.)
	 * @param mark
	 *            the item to store on the board
	 * @return boolean true if a piece is set
	 */
	public boolean set(int row, int column, char mark) {
		assert row >= 0 && row < DIMENSION;
		assert column >= 0 && column < DIMENSION;
		assert mark != '?';

		// out of bounds
		if ((row < 0) || (row >= DIMENSION) || (column < 0)
				|| (column >= DIMENSION)) {
			System.out.println("False");
			return false;
		}
		// only sets if space is blank
		if ((board[row][column]) == DEFAULT_CHAR) {
			board[row][column] = mark;
			// System.out.println("True");
			return true;
		} else {
			// System.out.println("False");
			return false;
		}
	}

	/**
	 * Get a piece on the board if its within the boundaries.
	 * 
	 * @param row
	 *            the row of the new piece
	 * @param column
	 *            the column of the new piece (Precondition: row and column
	 *            indicate a valid place on the board.)
	 * @return the item stored on the board at the given location
	 */
	public char get(int row, int column) {
		if ((row > DIMENSION) || (column > DIMENSION) || (row < 0)
				|| (column < 0)) {
			return DEFAULT_CHAR;
		}

		return board[row][column];
	}

	/**
	 * Create a string representing the board
	 * 
	 * @return a string containing multiple lines, including separators
	 */
	@Override
	public String toString() {
		String result = "";
		// Build the horizontal bar
		String separator = "\n-";
		for (int row = 1; row < DIMENSION; row++) {
			separator += "+-";
		}
		separator += "\n";

		for (int row = 0; row < DIMENSION; row++) {
			result += board[row][0]; // Include the first without
			// a leading bar
			for (int col = 1; col < DIMENSION; col++) {
				result += "|" + board[row][col];
			}
			if (row < DIMENSION - 1) {
				result += separator;
			}
		}

		return result;
	}

	/**
	 * Creates a deep copy of this board.
	 * 
	 * @return a deep copy of this board
	 */
	@Override
	public TicTacToeBoard clone() {
		// Create a new board
		TicTacToeBoard otherBoard = new TicTacToeBoard();

		// Copy the contents
		for (int row = 0; row < DIMENSION; row++) {
			for (int col = 0; col < DIMENSION; col++) {
				otherBoard.board[row][col] = this.board[row][col];
			}
		}

		return otherBoard;
	}

	/**
	 * Test for Horizontal Win case
	 * 
	 * @param player
	 *            a char to test
	 * @return boolean true if a win exist
	 */
	public boolean hasHorizontalWin(char player) {
		int counter = 0;

		// searches row for the given char and increases counter
		for (int row = 0; row < DIMENSION; row++) {
			for (int col = 0; col < DIMENSION; col++) {
				if ((board[row][col]) == player) {
					counter++;
				}
			}
			// if the char exists across the row = win
			if (counter == DIMENSION) {
				return true;
			}
			counter = 0;
		}
		return false;
	}

	/**
	 * Test for Vertical Win case
	 * 
	 * @param player
	 *            a char to test
	 * @return boolean true if a win exist
	 */
	public boolean hasVerticalWin(char player) {
		int counter = 0;

		// searches column for the given char and increases counter
		for (int row = 0; row < DIMENSION; row++) {
			for (int col = 0; col < DIMENSION; col++) {
				if ((board[col][row]) == player) {
					counter++;
				}
			}
			// if the char exists across the column = win
			if (counter == DIMENSION) {
				return true;
			}
			counter = 0;
		}
		return false;
	}

	/**
	 * Test for Diagonal Win case
	 * 
	 * @param player
	 *            a char to test
	 * @return boolean true if a win exist
	 */
	public boolean hasDiagonalWin(char player) {
		// checks for \ diagonal win
		int counter = 0;

		for (int i = 0; i < DIMENSION; i++) {
			if ((board[i][i]) == player) {
				counter++;
			}
		}
		if (counter == DIMENSION) {
			return true;
		}

		// checks for / diagonal win
		counter = 0;
		int col = DIMENSION - 1;
		for (int row = 0; row < DIMENSION; row++) {
			if (board[row][col] == player) {
				counter++;
			}
			col--;
		}
		if (counter == DIMENSION) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Boolean condition for wins
	 * 
	 * @param player
	 * @return
	 */
	public boolean hasWin(char player) {
		boolean hwin = hasHorizontalWin(player);
		boolean vwin = hasVerticalWin(player);
		boolean dwin = hasDiagonalWin(player);

		// System.out.println("Horizontal Win = "+hwin);
		// System.out.println("Vertical Win = "+vwin);
		// System.out.println("Diagonal Win = "+dwin);

		if (hwin == true) {
			return true;
		}
		if (vwin == true) {
			return true;
		}
		if (dwin == true) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Returns number of emptys
	 * 
	 * @return count
	 */
	public int emptySquares() {
		int count = 0;
		for (int row = 0; row < DIMENSION; row++) {
			for (int col = 0; col < DIMENSION; col++) {
				if (board[row][col] == ' ') {
					count++;
				}
			}
		}
		return count;
	}
}
